/**
 * 
 */
package it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.filehandlers;


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import it.unical.canonaco.rende.igpe.game.cbv.datastructure.Pair;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.stats.AbilityStats;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.stats.AbilityValue;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.stats.ScalingStats;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.stats.StartingRole;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.stats.StartingRoleFileFactory;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.stats.Stats;

/**
 * @author Massimo Canonaco
 *
 */
//TODO: this class is incomplete
public class ConcreteStartingRoleFactory implements StartingRoleFileFactory {
	/** */
	private static final String EXTENSION = ".xml";

	private static final String ROOT = "root";
	
	private static final String ROLE_NAME = "roleName";
	
	/** */
	private static final String BASE_STATS = "base";
	
	/** */
	private static final String PER_LEVEL_STATS = "perlevel";

	/** */
	private static final String ABILITIES_TAG = "abilities";
	
	private static final String SPELL = "spell";
	
	private static final String SPELL_ID = "id";
	
	/** */
	private static final String SPELL_NAME = "name";
	
	private static final String SPELL_TYPE = "type";
	private static final String SPELL_TYPE_PHYSICAL = "physical";
	private static final String SPELL_TYPE_MAGICAL = "magical";
	private static final String SPELL_TYPE_MODIFIER = "modifier";
	private static final String SPELL_TYPE_RECOVERY = "recovery";
	/** */
	private static final String SPELL_FRIENDLY = "friendly";
	
	private static final String SPELL_SELF_ONLY = "self";
	/** */
	private static final String SPELL_AREA_OF_EFFECT = "aoe";
	
	/** */
	private static final String SPELL_COST = "cost";
	
	/** */
	private static final String SPELL_RATIOS = "ratios";
	
	private static final String SPELL_RADIUS = "radius";
	/** */
	private static final String SPELL_SCALING_STAT = "scalingstat";
	
	private static final String SPELL_SCALING_AMOUNT = "amount";
	
	private static final String HEALTH_STAT = "health";
	private static final String MOVEMENT_RANGE_STAT = "mrange";
	private static final String ATTACK_RANGE_STAT = "arange";
	private static final String PHYSICAL_DAMAGE_STAT = "pdamage";
	private static final String MAGIC_DAMAGE_STAT = "mdamage";
	private static final String PHYSICAL_RESISTANCE_STAT = "presistance";
	private static final String MAGIC_RESISTANCE_STAT = "mresistance";

	
	private SAXParserFactory saxParserFactory;
	
	
	
	public ConcreteStartingRoleFactory() {
		
		if(saxParserFactory == null)
		{
			saxParserFactory = SAXParserFactory.newInstance();
		}
	}
	
	/** */
	@Override
	public String getExtension() {
		return EXTENSION;
	}
	
	@Override
	public StartingRole load(String path, String fileName)
	{
		Reader saxHandler = new Reader();
		try {
			saxParserFactory.newSAXParser().parse(new FileInputStream(path+File.separatorChar+checkFileName(fileName)), saxHandler);
		} catch (SAXException | IOException
				| ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
//		
//		AbilityStats as = saxHandler.startingRole.getAbility(0);
//		
//		System.out.println(as.getHealth());
//		System.out.println(as.getMovementRange());
//		System.out.println(as.getAttackRange());
//		System.out.println(as.getPhysicalForce());
//		System.out.println(as.getMagicForce());
//		System.out.println(as.getPhysicalResistance());
//		System.out.println(as.getMagicResistance());
//		Stats xlvl = saxHandler.startingRole.getPerLevelAbilities().get(0);
//		System.out.println(xlvl.getHealth());
//		System.out.println(xlvl.getMovementRange());
//		System.out.println(xlvl.getAttackRange());
//		System.out.println(xlvl.getPhysicalForce());
//		System.out.println(xlvl.getMagicForce());
//		System.out.println(xlvl.getPhysicalResistance());
//		System.out.println(xlvl.getMagicResistance());
//		
//		ScalingStats ss = as.getScalingAbilities();
//		
//		HashMap<Integer, LinkedList<Pair<Integer, Float>>> sss = ss.getScalingStat();
//		for(int key : sss.keySet()){
//			LinkedList<Pair<Integer, Float>> values = sss.get(key);
//			for(Pair<Integer, Float> ratio : values){
//			System.out.println("ssssssssssssssssssssssssssssssssss"+ratio.getFirst()+" "+ratio.getSecond());	
//			}
//			
//		}
//		
//		
//		System.out.println(as.getAbilityValue().getName());
//		System.out.println(as.getAbilityValue().getId());
//		System.out.println(as.getAbilityValue().isAreaOfEffect());
//		System.out.println(as.getAbilityValue().isFriendly());
//		System.out.println(as.getAbilityValue().getCost());
		
		return saxHandler.startingRole;
	}
	


	/** */
	private class Reader extends DefaultHandler 
	{
		private StartingRole startingRole;
		
		private String tmpStr;
		/** */
		private boolean abilitiesTag,
						perLevelTag,
						baseTag;
		
		private AbilityValue abilityValue;
		
		private ScalingStats scalingStats;
		
		private AbilityStats abilityStats;
		
		private Stats perLevelAbilityStats;
		
		private int spellIndex;
		private int charScalingIndex;
		private float scalingRatio;

		/** */
		public Reader() {
			
			startingRole = new StartingRole();
			abilitiesTag = baseTag = perLevelTag = false;
		}

		/** */
		@Override
		public void startElement(String uri, String localName, String elemName, Attributes attributes) throws SAXException {
			
			if(elemName.equalsIgnoreCase(ROOT))
				startingRole.setName(attributes.getValue(ROLE_NAME));
			else if(elemName.equalsIgnoreCase(BASE_STATS))
				baseTag = true;
			else if(elemName.equalsIgnoreCase(PER_LEVEL_STATS))
				perLevelTag = true;
			else if(elemName.equalsIgnoreCase(ABILITIES_TAG))
				abilitiesTag = true;
			else if(elemName.equalsIgnoreCase(SPELL)){
				// new spell, new scales and new infos
				scalingStats = new ScalingStats();
				abilityValue = new AbilityValue();
				abilityStats = new AbilityStats();
				perLevelAbilityStats = new Stats();
				abilityValue.setId(Integer.parseInt(attributes.getValue(SPELL_ID)));
				abilityValue.setName(attributes.getValue(SPELL_NAME));
				abilityValue.setFriendly(Boolean.parseBoolean(attributes.getValue(SPELL_FRIENDLY)));
				abilityValue.setCost(Float.parseFloat(attributes.getValue(SPELL_COST)));
				abilityValue.setAreaOfEffect(Boolean.parseBoolean(attributes.getValue(SPELL_AREA_OF_EFFECT)));
				abilityValue.setType(convertType(attributes.getValue(SPELL_TYPE)));
				abilityStats.setAbilityValue(abilityValue);
			}
			
			
			if(elemName.equalsIgnoreCase(HEALTH_STAT))
				spellIndex = Stats.HEALTH;
			else if(elemName.equalsIgnoreCase(MOVEMENT_RANGE_STAT))
				spellIndex = Stats.MOVEMENT_RANGE;
			else if(elemName.equalsIgnoreCase(ATTACK_RANGE_STAT))
				spellIndex = Stats.ATTACK_RANGE;
			else if(elemName.equalsIgnoreCase(PHYSICAL_DAMAGE_STAT))
				spellIndex = Stats.PHYSICAL_FORCE;
			else if(elemName.equalsIgnoreCase(MAGIC_DAMAGE_STAT))
				spellIndex = Stats.MAGIC_FORCE;
			else if(elemName.equalsIgnoreCase(PHYSICAL_RESISTANCE_STAT))
				spellIndex = Stats.PHYSICAL_RESISTANCE;
			else if(elemName.equalsIgnoreCase(MAGIC_RESISTANCE_STAT))
				spellIndex = Stats.MAGIC_RESISTANCE;
				
		}

		private int convertType(String value) {
			switch(value){
			case SPELL_TYPE_PHYSICAL:
				return AbilityValue.PHYSICAL_DAMAGE;
			case SPELL_TYPE_MAGICAL:
				return AbilityValue.MAGIC_DAMAGE;
			case SPELL_TYPE_MODIFIER:
				return AbilityValue.STATS_MODIFIER;
			case SPELL_TYPE_RECOVERY:
				return AbilityValue.RECOVERY;
			default :
				return -1;
			}
			
		}

		/** */
		@Override
		public void endElement(String uri, String localName, String elemName) throws SAXException {
			
			 if(elemName.equalsIgnoreCase(BASE_STATS))
				 baseTag = false;
			 else if(elemName.equalsIgnoreCase(PER_LEVEL_STATS))
				 perLevelTag = false;
//			 else if(elemName.equalsIgnoreCase(ABILITIES_TAG))
//				 abilities = false;
			 
			
			//If inside character branch
		 if(!abilitiesTag){
				if(baseTag)
					startingRole.getCharacteristics().setByIndex(spellIndex, Float.parseFloat(tmpStr));
			    else if(perLevelTag){
			    	startingRole.getPerLevelCharacteristics().setByIndex(spellIndex, Float.parseFloat(tmpStr));
			    	
			    }
		// else we're inside abilities branch
		 } else {
			 	  if(elemName.equalsIgnoreCase(SPELL_SELF_ONLY))
			 		  abilityValue.setSelfOnly(Boolean.parseBoolean(tmpStr));
			 	  else if(elemName.equalsIgnoreCase(SPELL_RADIUS))
			 		  abilityValue.setRadius(Integer.parseInt(tmpStr));
			 	  else if(elemName.equalsIgnoreCase(SPELL_SCALING_STAT))
					  charScalingIndex = Integer.parseInt(tmpStr);
				  else if(elemName.equalsIgnoreCase(SPELL_SCALING_AMOUNT))
					  scalingRatio = Float.parseFloat(tmpStr);
				  else if(elemName.equalsIgnoreCase(SPELL_RATIOS))
					  scalingStats.setAmountByIndexes(spellIndex, charScalingIndex, scalingRatio);
				  else if(elemName.equalsIgnoreCase(BASE_STATS))
					  abilityStats.setByIndex(spellIndex, Float.parseFloat(tmpStr));
				  else if(elemName.equalsIgnoreCase(PER_LEVEL_STATS))
					  perLevelAbilityStats.setByIndex(spellIndex, Float.parseFloat(tmpStr));
				 // spell is completely read: set all the variables to that spell
				  else if(elemName.equalsIgnoreCase(SPELL)){
					  abilityStats.setScalingAbilities(scalingStats);
					  startingRole.getAbilities().add(abilityStats);
					  startingRole.getPerLevelAbilities().add(perLevelAbilityStats);
				  }
						  
			  }
		}

		/** */
		@Override
		public void characters(char[] ch, int start, int length) throws SAXException {
			tmpStr = new String(ch, start, length);
		}
		
	}
	
	/** */
	@Override
	//TODO: save function
	public boolean save(String path, String fileName, StartingRole toSave) {
		return false;
	}
	
	/** */
	private String checkFileName(final String file)
	{
		if(file.endsWith(EXTENSION))
			return file;

		return file.concat(EXTENSION);
	}

}
